/*
 ------------------------------------------------------------------------------
 Copyright (C) 2009-2011 Eternal Games.

 This file is part of the Eternal Tech source code.

 The Eternal Tech source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Eternal Tech source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Eternal Tech source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// plane.cpp - Frustum plane library
//


#include "../../qcommon/qcommon.h"


/*
 ==================
 BoxOnPlaneSide

 TODO: Remove PLANE_NON_AXIAL check?
 ==================
*/
int BoxOnPlaneSide (const vec3_t mins, const vec3_t maxs, const cplane_t *plane)
{
	float	epsilon = 0.0f;
	float	dist1, dist2;

	// Fast axial cases
	if (plane->type < PLANE_NON_AXIAL)
	{
		if (plane->dist <= mins[plane->type])
			return PLANESIDE_FRONT;
		if (plane->dist >= maxs[plane->type])
			return PLANESIDE_BACK;

		return PLANESIDE_CROSS;
	}
	
	// General case
	switch (plane->signbits){
	case 0:
		dist1 = (plane->normal[0]*maxs[0] + plane->normal[1]*maxs[1] + plane->normal[2]*maxs[2]) - plane->dist;
		dist2 = (plane->normal[0]*mins[0] + plane->normal[1]*mins[1] + plane->normal[2]*mins[2]) - plane->dist;
		break;
	case 1:
		dist1 = (plane->normal[0]*mins[0] + plane->normal[1]*maxs[1] + plane->normal[2]*maxs[2]) - plane->dist;
		dist2 = (plane->normal[0]*maxs[0] + plane->normal[1]*mins[1] + plane->normal[2]*mins[2]) - plane->dist;
		break;
	case 2:
		dist1 = (plane->normal[0]*maxs[0] + plane->normal[1]*mins[1] + plane->normal[2]*maxs[2]) - plane->dist;
		dist2 = (plane->normal[0]*mins[0] + plane->normal[1]*maxs[1] + plane->normal[2]*mins[2]) - plane->dist;
		break;
	case 3:
		dist1 = (plane->normal[0]*mins[0] + plane->normal[1]*mins[1] + plane->normal[2]*maxs[2]) - plane->dist;
		dist2 = (plane->normal[0]*maxs[0] + plane->normal[1]*maxs[1] + plane->normal[2]*mins[2]) - plane->dist;
		break;
	case 4:
		dist1 = (plane->normal[0]*maxs[0] + plane->normal[1]*maxs[1] + plane->normal[2]*mins[2]) - plane->dist;
		dist2 = (plane->normal[0]*mins[0] + plane->normal[1]*mins[1] + plane->normal[2]*maxs[2]) - plane->dist;
		break;
	case 5:
		dist1 = (plane->normal[0]*mins[0] + plane->normal[1]*maxs[1] + plane->normal[2]*mins[2]) - plane->dist;
		dist2 = (plane->normal[0]*maxs[0] + plane->normal[1]*mins[1] + plane->normal[2]*maxs[2]) - plane->dist;
		break;
	case 6:
		dist1 = (plane->normal[0]*maxs[0] + plane->normal[1]*mins[1] + plane->normal[2]*mins[2]) - plane->dist;
		dist2 = (plane->normal[0]*mins[0] + plane->normal[1]*maxs[1] + plane->normal[2]*maxs[2]) - plane->dist;
		break;
	case 7:
		dist1 = (plane->normal[0]*mins[0] + plane->normal[1]*mins[1] + plane->normal[2]*mins[2]) - plane->dist;
		dist2 = (plane->normal[0]*maxs[0] + plane->normal[1]*maxs[1] + plane->normal[2]*maxs[2]) - plane->dist;
		break;
	default:
		dist1 = 0.0f;
		dist2 = 0.0f;
		break;
	}

	if (dist1 > epsilon && dist2 > epsilon)
		return PLANESIDE_FRONT;
	if (dist1 < -epsilon && dist2 < -epsilon)
		return PLANESIDE_BACK;

	return PLANESIDE_CROSS;
}

/*
 ==================
 SphereOnPlaneSide
 ==================
*/
int SphereOnPlaneSide (const vec3_t center, float radius, const cplane_t *plane)
{
	float	epsilon = 0.0f;
	float	dist;

	if (plane->type < PLANE_NON_AXIAL)
		dist = center[plane->type] - plane->dist;
	else
		dist = DotProduct(center, plane->normal) - plane->dist;

	if (dist > radius - epsilon)
		return PLANESIDE_FRONT;
	if (dist < -radius - epsilon)
		return PLANESIDE_BACK;

	return PLANESIDE_CROSS;
}

/*
 ==================
 PointOnPlaneSide
 ==================
*/
int PointOnPlaneSide (const vec3_t point, float epsilon, const cplane_t *plane)
{
	float	dist;

	if (plane->type < PLANE_NON_AXIAL)
		dist = point[plane->type] - plane->dist;
	else
		dist = DotProduct(point, plane->normal) - plane->dist;

	if (dist > epsilon)
		return PLANESIDE_FRONT;
	if (dist < -epsilon)
		return PLANESIDE_BACK;

	return PLANESIDE_ON;
}